#!/usr/bin/env python
# By: Kelcey Damage, 2012 & Kraig Amador, 2012
# RoyalYang modified on 20130105
'''
根据个人配置修改下面的api_url，apiKey，secret等内容。
apiKey和secret是在用户详情下的admin用户的apiKey和api_secret,
没有的需要再webUI上生成
'''
api_url = 'http://192.168.56.10:8080/client/api/'
apiKey = 'aaaiZ21Ve39tY3pmAnyrhKpv39tY3pmAnyrhjfG4tntKSRmn939tY3pmAnyrhKpvps-p8BI39tY3pmAnyrhKpv'
secret = 'hmRA_Nthkc9AhmRA_Nthkc9AhmRA_Nthkc9AhmRA_Nthkc9Ac5dmTGila7iAszQ75CdJy8xQQXBqwoDxR4D-dT'

import hashlib, hmac, string, base64, urllib
import json, urllib ,time, threading

class SignedAPICall(object):
    def __init__(self, api_url, apiKey, secret):
        self.api_url = api_url
        self.apiKey = apiKey
        self.secret = secret

    def request(self, args):
        args['apiKey'] = self.apiKey

        self.params = []
        self.__sort_request(args)
        self.__create_signature()
        self.__build_post_request()

    def __sort_request(self, args):
        keys = sorted(args.keys())

        for key in keys:
            self.params.append(key + '=' + urllib.quote_plus(args[key]))

    def __create_signature(self):
        self.query = '&'.join(self.params)
        digest = hmac.new(
            self.secret,
            msg=self.query.lower(),
            digestmod=hashlib.sha1).digest()
        self.signature = base64.b64encode(digest)

    def __build_post_request(self):
        self.query += '&signature=' + urllib.quote_plus(self.signature)
        self.value = self.api_url + '?' + self.query

class CloudStack(SignedAPICall):
    def __getattr__(self, name):
        def handlerFunction(*args, **kwargs):
            if kwargs:
                return self._make_request(name, kwargs)
            return self.__make_request(name, args[0])
        return handlerFunction

    def __http_get(self, url):
        response = urllib.urlopen(url)
        return response.read()

    def __make_request(self, command, args):
        args['response'] = 'json'
        args['command'] = command
        self.request(args)
        data = self.__http_get(self.value)
        # The response is of the format {commandresponse: actual-data}

        key = command.lower() + "response"
        return json.loads(data)[key]

class check_async_job(threading.Thread):
    global jobid
    def __init__(self, jobid):
        threading.Thread.__init__(self)
        self.thread_jobid = jobid
        self.thread_stop = False
    def run(self): #Overwrite run() method, put what you want the thread do here
        cnt=0
        while not self.thread_stop:
            jobstatus=0
            request = {'jobid': self.thread_jobid}
            if cnt<10 :
                result = api.queryAsyncJobResult(request)
                cnt+=1
                time.sleep(5)
                if result.has_key('jobstatus') and result.has_key('jobstatus')==1:
                    self.thread_stop = True
            else :
                print "timeout while checking jobid %d"%(self.thread_jobid)
                self.thread_stop = True
    def stop(self):
        self.thread_stop = True
#Usage
#api = CloudStack(api_url, apiKey, secret)

#stop zone
def stopzone() :
    request = { }
    result = api.listZones(request)
    if result.has_key('zone') :
        isneedstop = 'false'
        for zone in result['zone']:
            if zone['allocationstate']=='Enabled':
                isneedstop = 'true'
                print "Disabling %s" % zone['name']
                request = {'id': zone['id'], 'allocationstate' : 'Disabled'}
                result = api.updateZone(request)
        if isneedstop=='false':
            print "no Zone needs to be Disabled"
    else:
        print "no Zone needs to be Disabled"

#stop vms
def stopvms() :
    request = {'state': 'Running'}
    result = api.listVirtualMachines(request)
    if result.has_key('count'):
        #stop virtual machines
        for vm in result['virtualmachine']:
            print "Stopping %s" %vm['name']
            request = {'id': vm['id']}
            result = api.stopVirtualMachine(request)
            if result.has_key('jobid') :
                jobid=result['jobid']
                thread1=check_async_job(jobid).start()
    elif(len(result)==0):
        print "No VM needs to be stopped"
    else:
        print "shutdown VirtualMachines Failed"
        exit(1)

#stop system vms
def stopsysvm() :
    request = {'state': 'Running'}
    result = api.listSystemVms(request)
    if result.has_key('count') :
        for vm in result['systemvm']:
            print "Stopping %s" % vm['name']
            request = {'id': vm['id']}
            result = api.stopSystemVm(request)
            if result.has_key('jobid') :
                jobid=result['jobid']
                thread1=check_async_job(jobid).start()
    elif(len(result)==0):
        print "No SysVM needs to be stopped"
    else:
        print "shutdown SystemVms Failed"
        exit(1)

#stop vrouter
def stopVrouter():
    request = {'listall': 'true'}
    result = api.listRouters(request)
    hasrunrt = 0
    if result.has_key('router') :
        for vm in result['router']:
            if vm['state']=='Running' :
                hasrunrt=1
                print "Stopping %s" % vm['name']
                request = {'id': vm['id']}
                result = api.stopRouter(request)
                if result.has_key('jobid') :
                    jobid=result['jobid']
                    thread1=check_async_job(jobid).start()
    else:
        print "shutdown VRouter Failed"
    if(hasrunrt==0) :
        print "No VRouter needs to be stopped"

#check and wait
def chknwait() :
    while True:
        if(threading.activeCount()-1 != 0):
            print "wait while sysvms,vms and vrouters stopping"
            time.sleep(5)
            continue
        else:
            print "CloudStack has already stopped,please manully poweroff hosts,storages and mgtserver"
            exit()

#main method
if __name__=='__main__':
    api = CloudStack(api_url, apiKey, secret)
    stopzone()
    stopvms()
    stopsysvm()
    stopVrouter()
    chknwait()
